home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 476-500 / disk_497 / nlcalc / source / cloader.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  14KB  |  481 lines

  1. /*
  2.  *  CALC.C    Provides a calculator that opens on the active screen when
  3.  *            you press a specific key sequence.  Otherwise, the program
  4.  *            waits quitely in the background.
  5.  *
  6.  *              Copyright 1989 by Davide P. Cervone.
  7.  *  You may use this code, provided this copyright notice is kept intact.
  8.  */
  9.  
  10. #include "cLoader.h"
  11.  
  12. extern struct IntuitionBase *IntuitionBase;
  13. extern struct GfxBase *GfxBase;
  14.  
  15. static char *program   = PROGRAM;
  16. static char *copyright = COPYRIGHT;
  17.  
  18. static char *handler   = HANDLERCODE;       /* The name of the handler file */
  19. #define HANDLER          &(handler[2])      /* Handler without the L: */
  20.  
  21. static struct HandlerData *cHandlerData;    /* data shared with handler */
  22. static long Segment;                        /* The loaded handler segment */
  23. static struct Process *HandlerTask;         /* The process created */
  24.  
  25. static struct MsgPort *InputPort;           /* To talk to Input.Device */
  26. static struct IOStdReq *InputBlock;         /* IO block for Input.Device */
  27. static int    InputDevice;                  /* Is Input.Device open? */
  28. static int    VectorsSet;                   /* TRUE after SetFunction */
  29. static int    ProcStarted;                  /* TRUE acter CreateProc */
  30.  
  31. static UWORD  KeyCode = 0x50;               /* the keycode to activate Calc */
  32. static UWORD  Qualifiers = 0;               /*   and required qualifiers */
  33.  
  34.  
  35. struct KeywordDef                           /* keywords and ther qualifiers */
  36. {
  37.    char *Name;
  38.    UWORD Qualifier;
  39. };
  40.  
  41. static struct KeywordDef Keyword[] =
  42. {
  43.    {"LSHIFT",   IEQUALIFIER_LSHIFT},
  44.    {"RSHIFT",   IEQUALIFIER_RSHIFT},
  45.    {"SHIFT",    IEQUALIFIER_LSHIFT},
  46.    {"CAPSLOCK", IEQUALIFIER_CAPSLOCK},
  47.    {"CONTROL",  IEQUALIFIER_CONTROL},
  48.    {"LALT",     IEQUALIFIER_LALT},
  49.    {"RALT",     IEQUALIFIER_RALT},
  50.    {"ALT",      IEQUALIFIER_LALT},
  51.    {"LAMIGA",   IEQUALIFIER_LCOMMAND},
  52.    {"RAMIGA",   IEQUALIFIER_RCOMMAND},
  53.    {"AMIGA",    IEQUALIFIER_LCOMMAND},
  54.    {"LCOMMAND", IEQUALIFIER_LCOMMAND},
  55.    {"RCOMMAND", IEQUALIFIER_RCOMMAND},
  56.    {NULL}
  57. };
  58.  
  59.  
  60. /*
  61.  *  DoExit()
  62.  *
  63.  *  General purpose error-exit routine.  Print an error message if one was
  64.  *  supplied (it can have up to three parameters), and then clean up any
  65.  *  memory, libraries, etc. that need to be handled before exiting.
  66.  */
  67.  
  68. static void DoExit(s,x1,x2,x3)
  69. char *s, *x1, *x2, *x3;
  70. {
  71.    long status = EXIT_OK;
  72.    ULONG signals;
  73.    
  74.    if (s != NULL)
  75.    {
  76.       printf(s,x1,x2,x3);
  77.       printf("\n");
  78.       status = EXIT_ERROR;
  79.    }
  80.    if (VectorsSet)      UnSetVectors();
  81.    if (InputDevice)     CloseDevice(InputBlock);
  82.    if (InputBlock)      DeleteStdIO(InputBlock);
  83.    if (InputPort)       DeletePort(InputPort);
  84.    if (ProcStarted)
  85.    {
  86.       Signal(HandlerTask,ENDSIGNAL);
  87.       signals = Wait(ENDSIGNAL | SIGBREAKF_CTRL_C);
  88.       if (signals & SIGBREAKF_CTRL_C) printf("CTRL-C detected!!!\n");
  89.    }
  90.    if (Segment)                 UnLoadSeg(Segment);
  91.    if (IntuitionBase)           CloseLibrary(IntuitionBase);
  92.    if (GfxBase)                 CloseLibrary(GfxBase);
  93.    exit(status);
  94. }
  95.  
  96.  
  97. /*
  98.  *  CheckLibOpen()
  99.  *
  100.  *  Call OpenLibrary() for the specified library, and check that the 
  101.  *  open succeeded.
  102.  */
  103.  
  104. static void CheckLibOpen(lib,name,rev)
  105. APTR *lib;
  106. char *name;
  107. int rev;
  108. {
  109.    extern APTR OpenLibrary();
  110.  
  111.    if ((*lib = OpenLibrary(name,(LONG)rev)) == NULL)
  112.       DoExit("Can't open %s",name);
  113. }
  114.  
  115.  
  116. /*
  117.  *  CheckArguments()
  118.  *
  119.  *  For each command-line argument:
  120.  *    Look through the keyword list for the named argument.
  121.  *    If no match found, then
  122.  *      Check to see if the argument is an F-key name ('F1','F2', etc).
  123.  *      If so, then set the KeyCode accordingly,
  124.  *      Otherwise, try to read a keycode number.
  125.  *        If unsuccessful, then error.
  126.  *    Otherwise (a keyword was found)
  127.  *      so add the requested qualifier to the required qualifier list.
  128.  */
  129.  
  130. static void CheckArguments(argc,argv)
  131. int argc;
  132. char **argv;
  133. {
  134.    short i;
  135.    int NotFound;
  136.    long Code;
  137.  
  138.    while (--argc)
  139.    {
  140.       argv++;
  141.       for (i=0, NotFound=TRUE; Keyword[i].Name && NotFound; i++)
  142.          NotFound = stricmp(*argv,Keyword[i].Name);
  143.       if (NotFound)
  144.       {
  145.          if (((*argv)[0] == 'F' || (*argv)[0] == 'f') &&
  146.             (((*argv)[1] >= '1' && (*argv)[1] <= '9' && (*argv)[2] == 0) ||
  147.              ((*argv)[1] == '1' && (*argv)[2] == '0' && (*argv)[3] == 0)))
  148.          {
  149.             if ((*argv)[2] == 0)
  150.                KeyCode = 0x50 + (*argv)[1] - '1';
  151.               else
  152.                KeyCode = 0x59;
  153.          } else {
  154.             if (sscanf(*argv,"%x",&Code) != 1)
  155.                DoExit("Unrecognized keyword '%s'",*argv);
  156.             KeyCode = Code;
  157.          }
  158.       } else {
  159.          Qualifiers ^= Keyword[i-1].Qualifier;
  160.       }
  161.    }
  162. }
  163.  
  164.  
  165. /*
  166.  *  LoadHandler()
  167.  *
  168.  *  Try to LoadSeg the handler from the current directory, and if it is not
  169.  *  found, try the L: directory.  If neither can be loaded, exit with an
  170.  *  error message.  Once the handler is loaded, create a process from the
  171.  *  loaded segment (error if it could not be created) and set a flag so
  172.  *  that we can clean up if other errors occur.
  173.  */
  174.  
  175. static void LoadHandler()
  176. {
  177.    struct Process *theProcess;
  178.  
  179.    if ((Segment = LoadSeg(HANDLER)) == NULL)
  180.       if ((Segment = LoadSeg(handler)) == NULL)
  181.         DoExit("Can't load %s",handler);
  182.    theProcess = CreateProc(HANDLERTASKNAME,0L,Segment,2048L);
  183.    if (theProcess == NULL) DoExit("Can't Create Handler Process");
  184.    ProcStarted = TRUE;
  185. }
  186.  
  187.  
  188. /*
  189.  *  SetupHandler()
  190.  *
  191.  *  Look for the handler task, and error if it can't be found.  Get a message
  192.  *  port and a new StartupMessage structure to send the the Handler.  Put
  193.  *  the loader version number in the StartupMessage so the Handler can check
  194.  *  whether it is OK (if not, it will return a NULL HandlerData pointer).
  195.  *  Send the message to the Handler, and wait for a reply.  When it is
  196.  *  returned, get the HandlerData pointer, and free what we allocated.  
  197.  *  If the HandlerData is NULL, then there was a version mismatch reported 
  198.  *  by the Handler, otherwise, check the handler version to make sure we know
  199.  *  how to set it up.  Finally, set thePort the the Handler Port value.
  200.  */
  201.  
  202. static void SetupHandler(thePort)
  203. struct MsgPort **thePort;
  204. {
  205.    struct StartupMessage *sMessage;
  206.    struct MsgPort *rPort;
  207.    ULONG signals;
  208.    ULONG rSig;
  209.  
  210.    HandlerTask = FindTask(HANDLERTASKNAME);
  211.    if (HandlerTask == NULL) DoExit("Can't Find Handler Task");
  212.    NEWPORT(rPort);
  213.    if (NEWSTARTUP(sMessage))
  214.    {
  215.       rSig = ONE << rPort->mp_SigBit;
  216.       sMessage->sm_Message.mn_ReplyPort = rPort;
  217.       sMessage->sm_HandlerData = NULL;
  218.       sMessage->sm_ParentTask = (struct Task *)FindTask(NULL);
  219.       sMessage->sm_LoadVers = LOADVERS;
  220.       PutMsg(&(HandlerTask->pr_MsgPort),sMessage);
  221.       signals = Wait(rSig | SIGBREAKF_CTRL_C);
  222.       if (signals & SIGBREAKF_CTRL_C) DoExit("CTRL-C Detected!");
  223.       GETSTARTUP(rPort); cHandlerData = sMessage->sm_HandlerData;
  224.       FREESTARTUP(sMessage);
  225.       DeletePort(rPort);
  226.       if (cHandlerData == NULL) DoExit("%s reports a version mismatch",HANDLER);
  227.       if (var(MajVers) < MINHMAJVERS ||
  228.          (var(MajVers) == MINHMAJVERS && var(MinVers) < MINHMINVERS))
  229.             DoExit("Version mismatch with %s",HANDLER);
  230.       *thePort = &(cHandlerData->HandlerPort);
  231.    } else {
  232.       DeletePort(rPort);
  233.       DoExit("Can't Get Memory for Startup Message");
  234.    }
  235. }
  236.  
  237. /*
  238.  *  StartHandler()
  239.  *
  240.  *  Send the Handler the start signal so that it know everything is
  241.  *  set up for it.  Clear the old ParentTask pointer, since the task
  242.  *  that eventually removes the process may not be the same as the one
  243.  *  that started it.
  244.  */
  245.  
  246. void StartHandler()
  247. {
  248.    Signal(HandlerTask,STARTSIGNAL);
  249.  
  250.    Forbid();
  251.    VAR(ParentTask) = NULL;
  252.    Permit();
  253. }
  254.  
  255.  
  256. /*
  257.  *  StopHandler()
  258.  *
  259.  *  Send the Handler the stop signal, and wait for a reply (the Handler
  260.  *  may need to clean things up before we remove it).  Be sure that the
  261.  *  ParentTask points to us, and not to the original loader task, which 
  262.  *  may not be the same.
  263.  */
  264.  
  265. void StopHandler()
  266. {
  267.    ULONG signals;
  268.  
  269.    Forbid();
  270.    VAR(ParentTask) = (struct Task *)FindTask(NULL);
  271.    Permit();
  272.  
  273.    Signal(HandlerTask,ENDSIGNAL);
  274.    signals = Wait(ENDSIGNAL | SIGBREAKF_CTRL_C);
  275.    if (signals & SIGBREAKF_CTRL_C) DoExit("CTRL-C detected!!");
  276. }
  277.  
  278.  
  279. /*
  280.  *  TellInputDevice()
  281.  *
  282.  *  Create a port and I/O block, then open the input device.  Set up the
  283.  *  I/O block to add or remove the input handler, and send the request
  284.  *  to the input device.  Finally, close the device and delete the
  285.  *  I/O block and port.
  286.  */
  287.  
  288. void TellInputDevice(function)
  289. int function;
  290. {
  291.    long status;
  292.    extern struct MsgPort *CreatePort();
  293.    extern struct IOStdReq *CreateStdIO();
  294.  
  295.    if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
  296.    if ((InputBlock = CreateStdIO(InputPort)) == NULL)
  297.       DoExit("Can't Create Standard IO Block");
  298.    InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
  299.    if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
  300.    
  301.    InputBlock->io_Command = (long) function;
  302.    InputBlock->io_Data    = (APTR) var(Handler_Interrupt);
  303.    if (status = DoIO(InputBlock)) DoExit("Error from DoIO:  %ld",status);
  304.  
  305.    CloseDevice(InputBlock); InputDevice = FALSE;
  306.    DeleteStdIO(InputBlock); InputBlock = NULL;
  307.    DeletePort(InputPort);   InputPort = NULL;
  308. }
  309.  
  310.  
  311. /*
  312.  *  SetVectors()
  313.  *
  314.  *  Set the Intuition library vectors for the routines specified by the
  315.  *   handler.  Save the old routine pointers for later replacement.
  316.  */
  317.  
  318. void SetVectors()
  319. {
  320.    if (var(aCloseScreen) && var(OldCloseScreen))
  321.    {
  322.       VAR(OldCloseScreen) =
  323.          SetFunction(IntuitionBase,&LVOCloseScreen,var(aCloseScreen));
  324.       VectorsSet = TRUE;
  325.    }
  326. }
  327.  
  328.  
  329. /*
  330.  *  UnSetVectors()
  331.  *
  332.  *  Replace the old Intuition library vectors, but make sure that no one
  333.  *  else has changed them behind our back.  If they are not the same as
  334.  *  what we set them to originally, then put back the ones that we found,
  335.  *  and return an error status.
  336.  */
  337.  
  338. int UnSetVectors()
  339. {
  340.    long NewCloseScreen;
  341.    int status = TRUE;
  342.  
  343.    if (var(aCloseScreen) && var(OldCloseScreen))
  344.    {
  345.       Forbid();
  346.       NewCloseScreen =
  347.          SetFunction(IntuitionBase,&LVOCloseScreen,VAR(OldCloseScreen));
  348.       if (NewCloseScreen != (long) var(aCloseScreen))
  349.       {
  350.          SetFunction(IntuitionBase,&LVOCloseScreen,NewCloseScreen);
  351.          status = FALSE;
  352.       }
  353.       Permit();
  354.    }
  355.    return(status);
  356. }
  357.  
  358.  
  359. /*
  360.  *  SetVariables()
  361.  *
  362.  *  The HandlerData structure is used to allow the loading program to
  363.  *  set up variables needed by the handler (like Intuitionbase, etc.).  This
  364.  *  keeps the handler code to a minimum.  The loader retains pointers to the
  365.  *  linked lists, in case it needs to free memory on behalf of the handler.
  366.  */
  367.  
  368. void SetVariables(thePort)
  369. struct MsgPort *thePort;
  370. {
  371.    VAR(IntuitionBase) = IntuitionBase;
  372.    VAR(GfxBase) = GfxBase;
  373.    var(Segment) = Segment;
  374.    VAR(KeyCode) = KeyCode;
  375.    VAR(Qualifiers) = Qualifiers;
  376. }
  377.  
  378.  
  379. /*
  380.  *  GetVariables()
  381.  *
  382.  *  Look up the values stored in the HandlerData structure.  The 
  383.  *  Intuition library already was opened, and we will need to close it.
  384.  *  Similarly for the Graphics library.
  385.  */
  386.  
  387. void GetVariables(thePort)
  388. struct MsgPort *thePort;
  389. {
  390.    cHandlerData = (struct HandlerData *)thePort;
  391.    IntuitionBase = VAR(IntuitionBase);
  392.    GfxBase = VAR(GfxBase);
  393. }
  394.  
  395.  
  396. /*
  397.  *  Main()
  398.  *
  399.  *  Look for the Handler Process.
  400.  *  If the process does not exist, then the Handler is not active, so:
  401.  *    Handle the arguments (if any).
  402.  *    Open libraries.
  403.  *    Load the handler code and create the process.
  404.  *    Send the startup message to the process and get the HandlerData.
  405.  *    Set the variables needed by the handler.
  406.  *    Set the library vectors for the handler routines.
  407.  *    Add the input handler into the Input Device chain.
  408.  *    Add the port (supplied by the handler) into the system list so we
  409.  *      can find it later.
  410.  *    Signal the process that all is OK.
  411.  *    Notify the user that all is ready.
  412.  *  else (the process already exists, so the Handler already is active)
  413.  *    Get the pointer to the HandlerData structure from the port,
  414.  *      and get any variables we need from the structure.
  415.  *    Check that the loader versions are compatible.
  416.  *    Remove the input handler from the Input Device chain
  417.  *    Signal the Handler to stop, and wait for reply.
  418.  *    Try to remove the SetFunction calls.
  419.  *    If successfull, then
  420.  *      Remove the port from the system list.
  421.  *      Signal Handler to end and wait for reply.
  422.  *      Unload the handler segment list.
  423.  *      Notify the user that the Handler is deactivated.
  424.  *      Close libraries.
  425.  *    else (we could not replace the functions)
  426.  *      Put back the input handler.
  427.  *      Signal the Handler to continue.
  428.  *      Inform the user that the Handler can not be removed.
  429.  */
  430.  
  431. void main(argc,argv)
  432. int argc;
  433. char **argv;
  434. {
  435.    struct MsgPort *NamedPort;
  436.  
  437.    HandlerTask = FindTask(HANDLERTASKNAME);
  438.    if (HandlerTask == NULL)
  439.    {
  440.       if (argc > 1) CheckArguments(argc,argv);
  441.       CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
  442.       CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
  443.       LoadHandler();
  444.       SetupHandler(&NamedPort);
  445.       SetVariables(NamedPort);
  446.       SetVectors(NamedPort);
  447.       TellInputDevice(IND_ADDHANDLER);
  448.       AddPort(NamedPort);
  449.       StartHandler();
  450.       printf("%s v%d.%d.%d Installed\n",program,
  451.          var(MajVers),var(MinVers),LOADVERS);
  452.    } else {
  453.       NamedPort = FindPort(PORTNAME);
  454.       if (NamedPort == NULL) DoExit("Can't find port '%s'",PORTNAME);
  455.       GetVariables(NamedPort);
  456.       if (var(MinLoadVers) > LOADVERS || var(MajVers) < MINHMAJVERS ||
  457.          (var(MajVers) == MINHMAJVERS && var(MinVers) < MINHMINVERS))
  458.       {
  459.          printf("Loader version mismatch\n");
  460.          printf("%s not removed\n",program);
  461.       } else {
  462.          TellInputDevice(IND_REMHANDLER);
  463.          StopHandler();
  464.          if (UnSetVectors(NamedPort))
  465.          {
  466.             RemPort(NamedPort);
  467.             StopHandler();
  468.             UnLoadSeg(var(Segment));
  469.             printf("%s removed\n",program);
  470.             CloseLibrary(IntuitionBase);
  471.             CloseLibrary(GfxBase);
  472.          } else {
  473.             TellInputDevice(IND_ADDHANDLER);
  474.             StartHandler();
  475.             printf("SetFunction vectors have been changed!\n");
  476.             printf("Cannot remove %s\n",program);
  477.          }
  478.       }
  479.    }
  480. }
  481.